Libraries

library(readr)
library(tidyverse)
── Attaching packages ───────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 2.2.1     ✔ purrr   0.2.4
✔ tibble  1.4.2     ✔ dplyr   0.7.4
✔ tidyr   0.7.2     ✔ stringr 1.3.0
✔ ggplot2 2.2.1     ✔ forcats 0.3.0
── Conflicts ──────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(stringr)
library(tidytext)
library(lubridate)

Attaching package: ‘lubridate’

The following object is masked from ‘package:base’:

    date
library(wordcloud)
Loading required package: RColorBrewer
library(topicmodels)
library(tm)
Loading required package: NLP

Attaching package: ‘NLP’

The following object is masked from ‘package:ggplot2’:

    annotate
library(stopwords)

Attaching package: ‘stopwords’

The following object is masked from ‘package:tm’:

    stopwords
library(quanteda)
package ‘quanteda’ was built under R version 3.4.4Package version: 1.1.1
Parallel computing: 2 of 4 threads used.
See https://quanteda.io for tutorials and examples.

Attaching package: ‘quanteda’

The following objects are masked from ‘package:tm’:

    as.DocumentTermMatrix, stopwords

The following object is masked from ‘package:utils’:

    View

Insert data

songs <- read_csv("./data/songs.csv")
Parsed with column specification:
cols(
  index = col_integer(),
  song = col_character(),
  year = col_integer(),
  artist = col_character(),
  genre = col_character(),
  lyrics = col_character()
)

|=======                                                           |  10%   33 MB
|=======                                                           |  11%   34 MB
|=======                                                           |  11%   36 MB
|========                                                          |  12%   37 MB
|========                                                          |  12%   39 MB
|========                                                          |  13%   40 MB
|========                                                          |  13%   41 MB
|=========                                                         |  13%   42 MB
|=========                                                         |  14%   44 MB
|=========                                                         |  14%   45 MB
|==========                                                        |  15%   47 MB
|==========                                                        |  15%   49 MB
|==========                                                        |  16%   50 MB
|===========                                                       |  16%   51 MB
|===========                                                       |  17%   53 MB
|===========                                                       |  17%   54 MB
|============                                                      |  18%   55 MB
|============                                                      |  18%   56 MB
|============                                                      |  18%   58 MB
|============                                                      |  19%   59 MB
|=============                                                     |  19%   61 MB
|=============                                                     |  20%   62 MB
|=============                                                     |  20%   64 MB
|==============                                                    |  21%   65 MB
|==============                                                    |  21%   66 MB
|==============                                                    |  22%   68 MB
|===============                                                   |  22%   69 MB
|===============                                                   |  23%   71 MB
|===============                                                   |  23%   72 MB
|================                                                  |  23%   74 MB
|================                                                  |  24%   75 MB
|================                                                  |  24%   76 MB
|================                                                  |  25%   78 MB
|=================                                                 |  25%   79 MB
|=================                                                 |  26%   81 MB
|=================                                                 |  26%   82 MB
|==================                                                |  26%   83 MB
|==================                                                |  27%   84 MB
|==================                                                |  27%   86 MB
|==================                                                |  28%   87 MB
|===================                                               |  28%   89 MB
|===================                                               |  29%   90 MB
|===================                                               |  29%   92 MB
|====================                                              |  30%   93 MB
|====================                                              |  30%   94 MB
|====================                                              |  31%   96 MB
|=====================                                             |  31%   97 MB
|=====================                                             |  31%   99 MB
|=====================                                             |  32%  100 MB
|======================                                            |  33%  102 MB
|======================                                            |  33%  104 MB
|======================                                            |  34%  105 MB
|=======================                                           |  34%  107 MB
|=======================                                           |  35%  110 MB
|========================                                          |  36%  111 MB
|========================                                          |  36%  113 MB
|========================                                          |  37%  115 MB
|=========================                                         |  37%  116 MB
|=========================                                         |  38%  118 MB
|=========================                                         |  38%  119 MB
|==========================                                        |  39%  120 MB
|==========================                                        |  39%  122 MB
|==========================                                        |  39%  123 MB
|==========================                                        |  40%  124 MB
|===========================                                       |  40%  126 MB
|===========================                                       |  41%  127 MB
|===========================                                       |  41%  128 MB
|============================                                      |  42%  130 MB
|============================                                      |  42%  131 MB
|============================                                      |  43%  133 MB
|=============================                                     |  43%  134 MB
|=============================                                     |  43%  136 MB
|=============================                                     |  44%  137 MB
|==============================                                    |  44%  139 MB
|==============================                                    |  45%  140 MB
|==============================                                    |  45%  141 MB
|===============================                                   |  46%  143 MB
|===============================                                   |  46%  144 MB
|===============================                                   |  47%  145 MB
|===============================                                   |  47%  147 MB
|================================                                  |  48%  149 MB
|================================                                  |  48%  150 MB
|================================                                  |  49%  152 MB
|=================================                                 |  49%  153 MB
|=================================                                 |  49%  154 MB
|=================================                                 |  50%  156 MB
|==================================                                |  50%  157 MB
|==================================                                |  51%  158 MB
|==================================                                |  51%  160 MB
|==================================                                |  52%  161 MB
|===================================                               |  52%  162 MB
|===================================                               |  53%  164 MB
|===================================                               |  53%  166 MB
|====================================                              |  54%  167 MB
|====================================                              |  54%  168 MB
|====================================                              |  54%  169 MB
|=====================================                             |  55%  171 MB
|=====================================                             |  55%  172 MB
|=====================================                             |  56%  174 MB
|======================================                            |  56%  175 MB
|======================================                            |  57%  177 MB
|======================================                            |  57%  178 MB
|======================================                            |  58%  179 MB
|=======================================                           |  58%  181 MB
|=======================================                           |  58%  182 MB
|=======================================                           |  59%  184 MB
|========================================                          |  59%  185 MB
|========================================                          |  60%  186 MB
|========================================                          |  60%  187 MB
|========================================                          |  61%  189 MB
|=========================================                         |  61%  190 MB
|=========================================                         |  62%  192 MB
|=========================================                         |  62%  193 MB
|==========================================                        |  62%  194 MB
|==========================================                        |  63%  196 MB
|==========================================                        |  63%  197 MB
|===========================================                       |  64%  198 MB
|===========================================                       |  64%  200 MB
|===========================================                       |  65%  201 MB
|===========================================                       |  65%  202 MB
|============================================                      |  65%  204 MB
|============================================                      |  66%  205 MB
|============================================                      |  66%  207 MB
|=============================================                     |  67%  208 MB
|=============================================                     |  67%  210 MB
|=============================================                     |  68%  211 MB
|==============================================                    |  69%  213 MB
|==============================================                    |  69%  215 MB
|==============================================                    |  69%  216 MB
|===============================================                   |  70%  217 MB
|===============================================                   |  70%  219 MB
|===============================================                   |  71%  221 MB
|================================================                  |  72%  222 MB
|================================================                  |  72%  224 MB
|================================================                  |  72%  225 MB
|=================================================                 |  73%  226 MB
|=================================================                 |  73%  228 MB
|=================================================                 |  74%  229 MB
|==================================================                |  74%  231 MB
|==================================================                |  75%  232 MB
|==================================================                |  75%  233 MB
|==================================================                |  75%  235 MB
|===================================================               |  76%  236 MB
|===================================================               |  76%  237 MB
|===================================================               |  77%  239 MB
|====================================================              |  77%  240 MB
|====================================================              |  78%  242 MB
|====================================================              |  78%  243 MB
|====================================================              |  78%  244 MB
|=====================================================             |  79%  245 MB
|=====================================================             |  79%  247 MB
|=====================================================             |  80%  248 MB
|======================================================            |  80%  250 MB
|======================================================            |  81%  251 MB
|======================================================            |  81%  253 MB
|=======================================================           |  82%  254 MB
|=======================================================           |  82%  255 MB
|=======================================================           |  82%  256 MB
|=======================================================           |  83%  258 MB
|========================================================          |  83%  259 MB
|========================================================          |  84%  261 MB
|========================================================          |  84%  262 MB
|=========================================================         |  85%  264 MB
|=========================================================         |  85%  265 MB
|==========================================================        |  86%  268 MB
|==========================================================        |  87%  270 MB
|==========================================================        |  87%  271 MB
|===========================================================       |  88%  273 MB
|===========================================================       |  88%  274 MB
|===========================================================       |  89%  275 MB
|===========================================================       |  89%  277 MB
|============================================================      |  89%  278 MB
|============================================================      |  90%  279 MB
|============================================================      |  90%  280 MB
|============================================================      |  91%  281 MB
|=============================================================     |  91%  283 MB
|=============================================================     |  91%  284 MB
|=============================================================     |  92%  285 MB
|==============================================================    |  92%  287 MB
|==============================================================    |  93%  288 MB
|==============================================================    |  93%  289 MB
|==============================================================    |  94%  291 MB
|===============================================================   |  94%  292 MB
|===============================================================   |  95%  294 MB
|================================================================  |  95%  296 MB
|================================================================  |  96%  297 MB
|================================================================  |  96%  299 MB
|================================================================= |  97%  300 MB
|================================================================= |  97%  302 MB
|================================================================= |  98%  303 MB
|==================================================================|  98%  305 MB
|==================================================================|  98%  306 MB
|==================================================================|  99%  307 MB
|==================================================================|  99%  309 MB
|===================================================================| 100%  309 MB

DATA CLEANSING

Filter data, handle missing values

# Keep songs with 10 or more characters in the lyrics
songs <- 
  songs %>% 
  filter(str_length(lyrics) > 10)
  
# Detect the language of the song
library(cld3)
songs$lang <- detect_language(songs$lyrics)
# Filter the songs that are certainly english, the genre is not missing or 
# not available and the year is 1970 or later
songs <- 
  songs %>%
  filter(lang == "en" & 
           is.na(genre) == FALSE &
           year >= 1970 &
           genre != "Not Available")
  
songs$characters <- str_count(songs$lyrics)

_text cleaning

# Create a vector with stopwords
stopwords <- c(stopwords())
  
  
# Perform cleansing & stemming in lsong lyrics text
songs$lyrics <- tolower(songs$lyrics)
songs$lyrics <- removePunctuation(songs$lyrics)
songs$lyrics <- removeNumbers(songs$lyrics)
songs$lyrics <- stripWhitespace(songs$lyrics)
songs$lyrics <- removeWords(songs$lyrics, stopwords)
songs$lyrics <- stemDocument(songs$lyrics)
saveRDS(songs, file = "data/cleaned_data.RDS")

EXPLORATORY ANALYSIS

Are there any differences between different music genres

_How many songs per artist

songs <- readRDS(file = "data/cleaned_data.RDS")
songs %>% 
  group_by(artist) %>% 
  count() %>% 
  filter(n > 20) %>% 
  arrange(-n)
  • Not really informative. maybe

_How many songs per genre

songs %>% 
  group_by(genre) %>% 
  count() %>% 
  arrange(-n) %>% 
  ggplot() +
  geom_col(aes(reorder(genre, -n), n))

  • could choose specific genres for comparison. e.g. Rock, pop, hip-hop, metal, country, jazz, electronic.

_What kind of music uses more words

## number of characters per song
songs %>% 
  ggplot() +
  geom_boxplot(aes(genre, characters))

  • Hip-Hop seems to be the significantly different music genre.

_How many songs per genres & Artists

songs %>% 
  group_by(genre, artist) %>% 
  count() %>% 
  arrange(genre, -n)
  • Not informative

_How many songs per genres & Artists

songs %>% 
  group_by(artist, genre) %>% 
  count() %>% 
  arrange(artist, genre, -n) %>% 
  group_by(artist) %>% 
  summarise(N = n(), total_songs = sum(n)) %>% 
  arrange(-N)

** Possible problem as every artist belongs to just one genres. But it is known that a lot of artists do change their music genre through their career.

_How many songs per Year

songs %>% 
  group_by(year) %>% 
  count() 

*** There are a few songs with wrong year … ++

_How many songs per Decade and Genre

songs %>% 
  mutate(date = as_date(paste(as.character(songs$year), "-01", "-01"))) %>% 
  mutate(decade = floor_date(date, years(10))) %>% 
  group_by(decade, genre) %>% 
  summarise(N = n()) %>% 
  mutate(freq = round(N/sum(N), 2)) %>% 
  select(-N) %>% 
  spread(key = decade, value = freq) 
songs %>% 
  mutate(date = as_date(paste(as.character(songs$year), "-01", "-01"))) %>% 
  mutate(decade = floor_date(date, years(5))) %>% 
  group_by(decade, genre) %>% 
  summarise(N = n()) %>% 
  mutate(freq = round(N/sum(N), 2)) %>% 
  filter(genre %in% c("Country", "Hip-Hop", "Metal", "Pop", "Rock")) %>% 
  ggplot(aes(decade, freq, colour = genre)) +
  # geom_line() +
  geom_smooth(se = FALSE) +
  scale_y_continuous(labels = scales::percent_format()) +
  ggtitle("Smoothed frequency of total songs per Music Genre (top 5)")

NA
NA
NA

** I think it would be wrong to say things about music genres. Rock is Falling - Hip hop is raising ** could make a statistical test for counts, chi-square to show differences

_How many characters per Decade & Decade+Genre

songs %>% 
  mutate(date = as_date(paste(as.character(songs$year), "-01", "-01"))) %>% 
  mutate(decade = floor_date(date, years(10))) %>% 
  group_by(decade) %>% 
  summarise(characters = mean(characters, na.rm = TRUE)) %>% 
  # mutate(freq = round(N/sum(N), 2)) %>% 
  # select(-N) %>% 
  spread(key = decade, value = characters)
songs %>% 
  mutate(date = as_date(paste(as.character(songs$year), "-01", "-01"))) %>% 
  mutate(decade = floor_date(date, years(10))) %>% 
  group_by(decade, genre) %>% 
  summarise(characters = round(mean(characters, na.rm = TRUE), 0)) %>% 
  # mutate(freq = round(N/sum(N), 2)) %>% 
  # select(-N) %>% 
  spread(key = decade, value = characters) 
songs %>% 
  mutate(date = as_date(paste(as.character(songs$year), "-01", "-01"))) %>% 
  mutate(decade = floor_date(date, years(10))) %>% 
  group_by(decade, genre) %>% 
  summarise(characters = round(mean(characters, na.rm = TRUE), 0)) %>% 
 ggplot(aes(decade, characters, colour = genre)) +
  geom_line() +
  # geom_smooth(se = FALSE) +
  ggtitle("How much lyrics per song for Music Genre")

  
songs %>% 
  mutate(date = as_date(paste(as.character(songs$year), "-01", "-01"))) %>% 
  mutate(decade = floor_date(date, years(10))) %>% 
  group_by(decade) %>% 
  summarise(characters = round(mean(characters, na.rm = TRUE), 0)) %>% 
 ggplot(aes(decade, characters)) +
  geom_line() +
  # geom_smooth(se = FALSE) +
  ggtitle("How much lyrics per song per 5 year interval")

songs %>% 
  group_by(genre) %>% 
  summarise(characters = round(mean(characters, na.rm = TRUE), 0)) %>% 
ggplot(aes(reorder(genre, -characters), characters)) +
  geom_col() +
  ggtitle("Average lyrics characters per song for each music genre")

*** It seems that Hip-hop songs contain much more lyrics (almost double). ????

_Wordcloud

words <- 
  songs %>%
  unnest_tokens(word, lyrics) %>% 
  group_by(word) %>% 
  count() %>% 
  arrange(-n) %>% 
  head(100)
wordcloud(words = words$word, freq = words$n, max.words = 100)

_Wordcloud per genre - chech older … comparing

words <- 
  songs %>%
  unnest_tokens(word, lyrics) %>% 
  group_by(genre, word) %>% 
  count() %>% 
  arrange(-n) %>% 
  group_by(genre) %>% 
  top_n(n = 100, wt = n)
genres <- unique(words$genre)
for(i in 1:length(genres)){
  temp <- filter(words, genre == genres[i])
  
  # Create a word cloud
  par(bg="grey30")
  #png(file="/home/manos4/Analysis/002_Content/output/figs/WordCloud_all_posts.png",width=1000,height=700, bg="grey30")
  wordcloud(words = temp$word, freq = temp$n, col=terrain.colors(length(temp$word), alpha=0.9), random.order=FALSE, rot.per=0.3 )
  title(main =  genres[i] , font.main = 1, col.main = "cornsilk3", cex.main = 1.2)
  #dev.off()
}

pain could not be fit on page. It will not be plotted.light could not be fit on page. It will not be plotted.god could not be fit on page. It will not be plotted.ive could not be fit on page. It will not be plotted.hand could not be fit on page. It will not be plotted.insid could not be fit on page. It will not be plotted.say could not be fit on page. It will not be plotted.face could not be fit on page. It will not be plotted.got could not be fit on page. It will not be plotted.need could not be fit on page. It will not be plotted.kill could not be fit on page. It will not be plotted.caus could not be fit on page. It will not be plotted.fire could not be fit on page. It will not be plotted.sky could not be fit on page. It will not be plotted.right could not be fit on page. It will not be plotted.there could not be fit on page. It will not be plotted.wont could not be fit on page. It will not be plotted.lost could not be fit on page. It will not be plotted.hell could not be fit on page. It will not be plotted.black could not be fit on page. It will not be plotted.stand could not be fit on page. It will not be plotted.leav could not be fit on page. It will not be plotted.thing could not be fit on page. It will not be plotted.last could not be fit on page. It will not be plotted.hear could not be fit on page. It will not be plotted.word could not be fit on page. It will not be plotted.hate could not be fit on page. It will not be plotted.well could not be fit on page. It will not be plotted.everi could not be fit on page. It will not be plotted.tear could not be fit on page. It will not be plotted.keep could not be fit on page. It will not be plotted.head could not be fit on page. It will not be plotted.think could not be fit on page. It will not be plotted.wait could not be fit on page. It will not be plotted.chorus could not be fit on page. It will not be plotted.forev could not be fit on page. It will not be plotted.alon could not be fit on page. It will not be plotted.

gone could not be fit on page. It will not be plotted.thought could not be fit on page. It will not be plotted.

gone could not be fit on page. It will not be plotted.

NA

*** Print top-5 genres

_How much they repeat themselves - Rechedule code from ….

MODELLING ON GENRES

_Create the model

# _Build Model ###############################################################
  
# split into words
by_word <- 
  songs %>% 
  unnest_tokens(word, lyrics)
# find document-word counts
word_counts <- 
  by_word %>%
  count(song, word, sort = TRUE) %>%
  ungroup()
word_counts
songs_dtm <- word_counts %>%
  cast_dtm(song, word, n)
songs_dtm
<<DocumentTermMatrix (documents: 151622, terms: 181138)>>
Non-/sparse entries: 13271052/27451234784
Sparsity           : 100%
Maximal term length: 247
Weighting          : term frequency (tf)
#songs_lda <- LDA(songs_dtm, k = 4, control = list(seed = 1234))
songs_lda <- LDA(songs_dtm, k = 3, control = list(seed = 1234))
#songs_lda_2 <- LDA(songs_dtm, k = 2, control = list(seed = 1234))
save(songs_lda, file = "objects/songs_lda_3.RDA")
  • Create another model with 2 groups to check hip-hop & metal Vs the rest

_Top terms per Topic

 # _Calculate Tables ##########################################################
  library(tidytext)
  
  ap_topics <- tidy(songs_lda, matrix = "gamma")
  
  top_terms <- 
    ap_topics %>%
    group_by(topic) %>%
    top_n(10, gamma) %>%
    ungroup() %>%
    arrange(topic, -gamma) %>% 
    rename(prob = gamma)
  
  top_terms
LS0tCnRpdGxlOiAiSW5pdGlhbCBhbmFseXNpcyBvbiBzb25nIGx5cmljcywgdXNpbmcgI3RpZHl0ZXgiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCgojIExpYnJhcmllcwoKYGBge3J9CmxpYnJhcnkocmVhZHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkodGlkeXRleHQpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeSh0b3BpY21vZGVscykKbGlicmFyeSh0bSkKbGlicmFyeShzdG9wd29yZHMpCmxpYnJhcnkocXVhbnRlZGEpCmBgYAoKCiMgSW5zZXJ0IGRhdGEKCmBgYHtyfQoKc29uZ3MgPC0gcmVhZF9jc3YoIi4vZGF0YS9zb25ncy5jc3YiKQoKYGBgCgoKIyBEQVRBIENMRUFOU0lORwoKCiMjIEZpbHRlciBkYXRhLCBoYW5kbGUgbWlzc2luZyB2YWx1ZXMKCmBgYHtyfQoKIyBLZWVwIHNvbmdzIHdpdGggMTAgb3IgbW9yZSBjaGFyYWN0ZXJzIGluIHRoZSBseXJpY3MKc29uZ3MgPC0gCiAgc29uZ3MgJT4lIAogIGZpbHRlcihzdHJfbGVuZ3RoKGx5cmljcykgPiAxMCkKICAKIyBEZXRlY3QgdGhlIGxhbmd1YWdlIG9mIHRoZSBzb25nCmxpYnJhcnkoY2xkMykKc29uZ3MkbGFuZyA8LSBkZXRlY3RfbGFuZ3VhZ2Uoc29uZ3MkbHlyaWNzKQoKIyBGaWx0ZXIgdGhlIHNvbmdzIHRoYXQgYXJlIGNlcnRhaW5seSBlbmdsaXNoLCB0aGUgZ2VucmUgaXMgbm90IG1pc3Npbmcgb3IgCiMgbm90IGF2YWlsYWJsZSBhbmQgdGhlIHllYXIgaXMgMTk3MCBvciBsYXRlcgoKc29uZ3MgPC0gCiAgc29uZ3MgJT4lCiAgZmlsdGVyKGxhbmcgPT0gImVuIiAmIAogICAgICAgICAgIGlzLm5hKGdlbnJlKSA9PSBGQUxTRSAmCiAgICAgICAgICAgeWVhciA+PSAxOTcwICYKICAgICAgICAgICBnZW5yZSAhPSAiTm90IEF2YWlsYWJsZSIpCiAgCnNvbmdzJGNoYXJhY3RlcnMgPC0gc3RyX2NvdW50KHNvbmdzJGx5cmljcykKCmBgYAoKCgojIyBfdGV4dCBjbGVhbmluZwoKYGBge3J9CgoKIyBDcmVhdGUgYSB2ZWN0b3Igd2l0aCBzdG9wd29yZHMKc3RvcHdvcmRzIDwtIGMoc3RvcHdvcmRzKCkpCiAgCiAgCiMgUGVyZm9ybSBjbGVhbnNpbmcgJiBzdGVtbWluZyBpbiBsc29uZyBseXJpY3MgdGV4dApzb25ncyRseXJpY3MgPC0gdG9sb3dlcihzb25ncyRseXJpY3MpCnNvbmdzJGx5cmljcyA8LSByZW1vdmVQdW5jdHVhdGlvbihzb25ncyRseXJpY3MpCnNvbmdzJGx5cmljcyA8LSByZW1vdmVOdW1iZXJzKHNvbmdzJGx5cmljcykKc29uZ3MkbHlyaWNzIDwtIHN0cmlwV2hpdGVzcGFjZShzb25ncyRseXJpY3MpCnNvbmdzJGx5cmljcyA8LSByZW1vdmVXb3Jkcyhzb25ncyRseXJpY3MsIHN0b3B3b3JkcykKc29uZ3MkbHlyaWNzIDwtIHN0ZW1Eb2N1bWVudChzb25ncyRseXJpY3MpCgoKc2F2ZVJEUyhzb25ncywgZmlsZSA9ICJkYXRhL2NsZWFuZWRfZGF0YS5SRFMiKQoKYGBgCgoKIyBFWFBMT1JBVE9SWSBBTkFMWVNJUwoKIyBBcmUgdGhlcmUgYW55IGRpZmZlcmVuY2VzIGJldHdlZW4gZGlmZmVyZW50IG11c2ljIGdlbnJlcwoKIyMgX0hvdyBtYW55IHNvbmdzIHBlciBhcnRpc3QKCmBgYHtyfQpzb25ncyA8LSByZWFkUkRTKGZpbGUgPSAiZGF0YS9jbGVhbmVkX2RhdGEuUkRTIikKCgpzb25ncyAlPiUgCiAgZ3JvdXBfYnkoYXJ0aXN0KSAlPiUgCiAgY291bnQoKSAlPiUgCiAgZmlsdGVyKG4gPiAyMCkgJT4lIAogIGFycmFuZ2UoLW4pCgpgYGAKKiBOb3QgcmVhbGx5IGluZm9ybWF0aXZlLiBtYXliZSAKCiMjIF9Ib3cgbWFueSBzb25ncyBwZXIgZ2VucmUKCmBgYHtyfQpzb25ncyAlPiUgCiAgZ3JvdXBfYnkoZ2VucmUpICU+JSAKICBjb3VudCgpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fY29sKGFlcyhyZW9yZGVyKGdlbnJlLCAtbiksIG4pKQoKYGBgCgoqIGNvdWxkIGNob29zZSBzcGVjaWZpYyBnZW5yZXMgZm9yIGNvbXBhcmlzb24uIGUuZy4gUm9jaywgcG9wLCBoaXAtaG9wLCBtZXRhbCwgY291bnRyeSwgamF6eiwgZWxlY3Ryb25pYy4gCgojIyBfV2hhdCBraW5kIG9mIG11c2ljIHVzZXMgbW9yZSB3b3JkcwoKYGBge3J9CgojIyBudW1iZXIgb2YgY2hhcmFjdGVycyBwZXIgc29uZwpzb25ncyAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoZ2VucmUsIGNoYXJhY3RlcnMpKQoKYGBgCiogSGlwLUhvcCBzZWVtcyB0byBiZSB0aGUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgbXVzaWMgZ2VucmUuIAoKIyMgX0hvdyBtYW55IHNvbmdzIHBlciBnZW5yZXMgJiBBcnRpc3RzCgpgYGB7cn0KCnNvbmdzICU+JSAKICBncm91cF9ieShnZW5yZSwgYXJ0aXN0KSAlPiUgCiAgY291bnQoKSAlPiUgCiAgYXJyYW5nZShnZW5yZSwgLW4pCgpgYGAKKiBOb3QgaW5mb3JtYXRpdmUKCiMjIF9Ib3cgbWFueSBzb25ncyBwZXIgZ2VucmVzICYgQXJ0aXN0cwoKYGBge3J9Cgpzb25ncyAlPiUgCiAgZ3JvdXBfYnkoYXJ0aXN0LCBnZW5yZSkgJT4lIAogIGNvdW50KCkgJT4lIAogIGFycmFuZ2UoYXJ0aXN0LCBnZW5yZSwgLW4pICU+JSAKICBncm91cF9ieShhcnRpc3QpICU+JSAKICBzdW1tYXJpc2UoTiA9IG4oKSwgdG90YWxfc29uZ3MgPSBzdW0obikpICU+JSAKICBhcnJhbmdlKC1OKQoKYGBgCioqIFBvc3NpYmxlIHByb2JsZW0gYXMgZXZlcnkgYXJ0aXN0IGJlbG9uZ3MgdG8ganVzdCBvbmUgZ2VucmVzLiBCdXQgaXQgaXMga25vd24gCnRoYXQgYSBsb3Qgb2YgYXJ0aXN0cyBkbyBjaGFuZ2UgdGhlaXIgbXVzaWMgZ2VucmUgdGhyb3VnaCB0aGVpciBjYXJlZXIuCgojIyBfSG93IG1hbnkgc29uZ3MgcGVyIFllYXIKCmBgYHtyfQoKc29uZ3MgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JSAKICBjb3VudCgpIAoKYGBgCioqKiBUaGVyZSBhcmUgYSBmZXcgc29uZ3Mgd2l0aCB3cm9uZyB5ZWFyIC4uLiAKKysKCiMjIF9Ib3cgbWFueSBzb25ncyBwZXIgRGVjYWRlIGFuZCBHZW5yZQoKYGBge3J9Cgpzb25ncyAlPiUgCiAgbXV0YXRlKGRhdGUgPSBhc19kYXRlKHBhc3RlKGFzLmNoYXJhY3Rlcihzb25ncyR5ZWFyKSwgIi0wMSIsICItMDEiKSkpICU+JSAKICBtdXRhdGUoZGVjYWRlID0gZmxvb3JfZGF0ZShkYXRlLCB5ZWFycygxMCkpKSAlPiUgCiAgZ3JvdXBfYnkoZGVjYWRlLCBnZW5yZSkgJT4lIAogIHN1bW1hcmlzZShOID0gbigpKSAlPiUgCiAgbXV0YXRlKGZyZXEgPSByb3VuZChOL3N1bShOKSwgMikpICU+JSAKICBzZWxlY3QoLU4pICU+JSAKICBzcHJlYWQoa2V5ID0gZGVjYWRlLCB2YWx1ZSA9IGZyZXEpIAoKc29uZ3MgJT4lIAogIG11dGF0ZShkYXRlID0gYXNfZGF0ZShwYXN0ZShhcy5jaGFyYWN0ZXIoc29uZ3MkeWVhciksICItMDEiLCAiLTAxIikpKSAlPiUgCiAgbXV0YXRlKGRlY2FkZSA9IGZsb29yX2RhdGUoZGF0ZSwgeWVhcnMoNSkpKSAlPiUgCiAgZ3JvdXBfYnkoZGVjYWRlLCBnZW5yZSkgJT4lIAogIHN1bW1hcmlzZShOID0gbigpKSAlPiUgCiAgbXV0YXRlKGZyZXEgPSByb3VuZChOL3N1bShOKSwgMikpICU+JSAKICBmaWx0ZXIoZ2VucmUgJWluJSBjKCJDb3VudHJ5IiwgIkhpcC1Ib3AiLCAiTWV0YWwiLCAiUG9wIiwgIlJvY2siKSkgJT4lIAogIGdncGxvdChhZXMoZGVjYWRlLCBmcmVxLCBjb2xvdXIgPSBnZW5yZSkpICsKICAjIGdlb21fbGluZSgpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSkgKwogIGdndGl0bGUoIlNtb290aGVkIGZyZXF1ZW5jeSBvZiB0b3RhbCBzb25ncyBwZXIgTXVzaWMgR2VucmUgKHRvcCA1KSIpCiAgCiAgCiAgCgoKYGBgCioqIEkgdGhpbmsgaXQgd291bGQgYmUgd3JvbmcgdG8gc2F5IHRoaW5ncyBhYm91dCBtdXNpYyBnZW5yZXMuIFJvY2sgaXMgRmFsbGluZyAtIEhpcCBob3AgaXMgcmFpc2luZwoqKiBjb3VsZCBtYWtlIGEgc3RhdGlzdGljYWwgdGVzdCBmb3IgY291bnRzLCBjaGktc3F1YXJlIHRvIHNob3cgZGlmZmVyZW5jZXMKCiMjIF9Ib3cgbWFueSBjaGFyYWN0ZXJzIHBlciBEZWNhZGUgJiBEZWNhZGUrR2VucmUKCmBgYHtyfQoKc29uZ3MgJT4lIAogIG11dGF0ZShkYXRlID0gYXNfZGF0ZShwYXN0ZShhcy5jaGFyYWN0ZXIoc29uZ3MkeWVhciksICItMDEiLCAiLTAxIikpKSAlPiUgCiAgbXV0YXRlKGRlY2FkZSA9IGZsb29yX2RhdGUoZGF0ZSwgeWVhcnMoMTApKSkgJT4lIAogIGdyb3VwX2J5KGRlY2FkZSkgJT4lIAogIHN1bW1hcmlzZShjaGFyYWN0ZXJzID0gbWVhbihjaGFyYWN0ZXJzLCBuYS5ybSA9IFRSVUUpKSAlPiUgCiAgIyBtdXRhdGUoZnJlcSA9IHJvdW5kKE4vc3VtKE4pLCAyKSkgJT4lIAogICMgc2VsZWN0KC1OKSAlPiUgCiAgc3ByZWFkKGtleSA9IGRlY2FkZSwgdmFsdWUgPSBjaGFyYWN0ZXJzKQoKCnNvbmdzICU+JSAKICBtdXRhdGUoZGF0ZSA9IGFzX2RhdGUocGFzdGUoYXMuY2hhcmFjdGVyKHNvbmdzJHllYXIpLCAiLTAxIiwgIi0wMSIpKSkgJT4lIAogIG11dGF0ZShkZWNhZGUgPSBmbG9vcl9kYXRlKGRhdGUsIHllYXJzKDEwKSkpICU+JSAKICBncm91cF9ieShkZWNhZGUsIGdlbnJlKSAlPiUgCiAgc3VtbWFyaXNlKGNoYXJhY3RlcnMgPSByb3VuZChtZWFuKGNoYXJhY3RlcnMsIG5hLnJtID0gVFJVRSksIDApKSAlPiUgCiAgIyBtdXRhdGUoZnJlcSA9IHJvdW5kKE4vc3VtKE4pLCAyKSkgJT4lIAogICMgc2VsZWN0KC1OKSAlPiUgCiAgc3ByZWFkKGtleSA9IGRlY2FkZSwgdmFsdWUgPSBjaGFyYWN0ZXJzKSAKCgoKCnNvbmdzICU+JSAKICBtdXRhdGUoZGF0ZSA9IGFzX2RhdGUocGFzdGUoYXMuY2hhcmFjdGVyKHNvbmdzJHllYXIpLCAiLTAxIiwgIi0wMSIpKSkgJT4lIAogIG11dGF0ZShkZWNhZGUgPSBmbG9vcl9kYXRlKGRhdGUsIHllYXJzKDEwKSkpICU+JSAKICBncm91cF9ieShkZWNhZGUsIGdlbnJlKSAlPiUgCiAgc3VtbWFyaXNlKGNoYXJhY3RlcnMgPSByb3VuZChtZWFuKGNoYXJhY3RlcnMsIG5hLnJtID0gVFJVRSksIDApKSAlPiUgCiBnZ3Bsb3QoYWVzKGRlY2FkZSwgY2hhcmFjdGVycywgY29sb3VyID0gZ2VucmUpKSArCiAgZ2VvbV9saW5lKCkgKwogICMgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSkgKwogIGdndGl0bGUoIkhvdyBtdWNoIGx5cmljcyBwZXIgc29uZyBmb3IgTXVzaWMgR2VucmUiKQogIApzb25ncyAlPiUgCiAgbXV0YXRlKGRhdGUgPSBhc19kYXRlKHBhc3RlKGFzLmNoYXJhY3Rlcihzb25ncyR5ZWFyKSwgIi0wMSIsICItMDEiKSkpICU+JSAKICBtdXRhdGUoZGVjYWRlID0gZmxvb3JfZGF0ZShkYXRlLCB5ZWFycygxMCkpKSAlPiUgCiAgZ3JvdXBfYnkoZGVjYWRlKSAlPiUgCiAgc3VtbWFyaXNlKGNoYXJhY3RlcnMgPSByb3VuZChtZWFuKGNoYXJhY3RlcnMsIG5hLnJtID0gVFJVRSksIDApKSAlPiUgCiBnZ3Bsb3QoYWVzKGRlY2FkZSwgY2hhcmFjdGVycykpICsKICBnZW9tX2xpbmUoKSArCiAgIyBnZW9tX3Ntb290aChzZSA9IEZBTFNFKSArCiAgZ2d0aXRsZSgiSG93IG11Y2ggbHlyaWNzIHBlciBzb25nIHBlciA1IHllYXIgaW50ZXJ2YWwiKQoKCnNvbmdzICU+JSAKICBncm91cF9ieShnZW5yZSkgJT4lIAogIHN1bW1hcmlzZShjaGFyYWN0ZXJzID0gcm91bmQobWVhbihjaGFyYWN0ZXJzLCBuYS5ybSA9IFRSVUUpLCAwKSkgJT4lIApnZ3Bsb3QoYWVzKHJlb3JkZXIoZ2VucmUsIC1jaGFyYWN0ZXJzKSwgY2hhcmFjdGVycykpICsKICBnZW9tX2NvbCgpICsKICBnZ3RpdGxlKCJBdmVyYWdlIGx5cmljcyBjaGFyYWN0ZXJzIHBlciBzb25nIGZvciBlYWNoIG11c2ljIGdlbnJlIikKCmBgYAoqKiogSXQgc2VlbXMgdGhhdCBIaXAtaG9wIHNvbmdzIGNvbnRhaW4gbXVjaCBtb3JlIGx5cmljcyAoYWxtb3N0IGRvdWJsZSkuID8/Pz8gCgoKIyMgX1dvcmRjbG91ZCAKCmBgYHtyfQp3b3JkcyA8LSAKICBzb25ncyAlPiUKICB1bm5lc3RfdG9rZW5zKHdvcmQsIGx5cmljcykgJT4lIAogIGdyb3VwX2J5KHdvcmQpICU+JSAKICBjb3VudCgpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgaGVhZCgxMDApCgp3b3JkY2xvdWQod29yZHMgPSB3b3JkcyR3b3JkLCBmcmVxID0gd29yZHMkbiwgbWF4LndvcmRzID0gMTAwKQpgYGAKCgoKIyMgX1dvcmRjbG91ZCBwZXIgZ2VucmUgIC0gY2hlY2ggb2xkZXIgLi4uIGNvbXBhcmluZwoKYGBge3J9CndvcmRzIDwtIAogIHNvbmdzICU+JQogIHVubmVzdF90b2tlbnMod29yZCwgbHlyaWNzKSAlPiUgCiAgZ3JvdXBfYnkoZ2VucmUsIHdvcmQpICU+JSAKICBjb3VudCgpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgZ3JvdXBfYnkoZ2VucmUpICU+JSAKICB0b3BfbihuID0gMTAwLCB3dCA9IG4pCgpnZW5yZXMgPC0gdW5pcXVlKHdvcmRzJGdlbnJlKQoKZm9yKGkgaW4gMTpsZW5ndGgoZ2VucmVzKSl7CiAgdGVtcCA8LSBmaWx0ZXIod29yZHMsIGdlbnJlID09IGdlbnJlc1tpXSkKICAKICAjIENyZWF0ZSBhIHdvcmQgY2xvdWQKICBwYXIoYmc9ImdyZXkzMCIpCiAgI3BuZyhmaWxlPSIvaG9tZS9tYW5vczQvQW5hbHlzaXMvMDAyX0NvbnRlbnQvb3V0cHV0L2ZpZ3MvV29yZENsb3VkX2FsbF9wb3N0cy5wbmciLHdpZHRoPTEwMDAsaGVpZ2h0PTcwMCwgYmc9ImdyZXkzMCIpCiAgd29yZGNsb3VkKHdvcmRzID0gdGVtcCR3b3JkLCBmcmVxID0gdGVtcCRuLCBjb2w9dGVycmFpbi5jb2xvcnMobGVuZ3RoKHRlbXAkd29yZCksIGFscGhhPTAuOSksIHJhbmRvbS5vcmRlcj1GQUxTRSwgcm90LnBlcj0wLjMgKQogIHRpdGxlKG1haW4gPSAgZ2VucmVzW2ldICwgZm9udC5tYWluID0gMSwgY29sLm1haW4gPSAiY29ybnNpbGszIiwgY2V4Lm1haW4gPSAxLjIpCiAgI2Rldi5vZmYoKQp9CiAgCmBgYAoKKioqIFByaW50IHRvcC01IGdlbnJlcwoKIyMgX0hvdyBtdWNoIHRoZXkgcmVwZWF0IHRoZW1zZWx2ZXMgLSBSZWNoZWR1bGUgY29kZSBmcm9tIC4uLi4KCgoKCiMgTU9ERUxMSU5HIE9OIEdFTlJFUwoKIyMgX0NyZWF0ZSB0aGUgbW9kZWwKCmBgYHtyfQojIF9CdWlsZCBNb2RlbCAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAKCiMgc3BsaXQgaW50byB3b3JkcwpieV93b3JkIDwtIAogIHNvbmdzICU+JSAKICB1bm5lc3RfdG9rZW5zKHdvcmQsIGx5cmljcykKCiMgZmluZCBkb2N1bWVudC13b3JkIGNvdW50cwp3b3JkX2NvdW50cyA8LSAKICBieV93b3JkICU+JQogIGNvdW50KHNvbmcsIHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUKICB1bmdyb3VwKCkKCndvcmRfY291bnRzCgoKc29uZ3NfZHRtIDwtIHdvcmRfY291bnRzICU+JQogIGNhc3RfZHRtKHNvbmcsIHdvcmQsIG4pCgpzb25nc19kdG0KCgojc29uZ3NfbGRhIDwtIExEQShzb25nc19kdG0sIGsgPSA0LCBjb250cm9sID0gbGlzdChzZWVkID0gMTIzNCkpCnNvbmdzX2xkYSA8LSBMREEoc29uZ3NfZHRtLCBrID0gMywgY29udHJvbCA9IGxpc3Qoc2VlZCA9IDEyMzQpKQojc29uZ3NfbGRhXzIgPC0gTERBKHNvbmdzX2R0bSwgayA9IDIsIGNvbnRyb2wgPSBsaXN0KHNlZWQgPSAxMjM0KSkKCgpzYXZlKHNvbmdzX2xkYSwgZmlsZSA9ICJvYmplY3RzL3NvbmdzX2xkYV8zLlJEQSIpCgpgYGAKKiBDcmVhdGUgYW5vdGhlciBtb2RlbCB3aXRoIDIgZ3JvdXBzIHRvIGNoZWNrIGhpcC1ob3AgJiBtZXRhbCBWcyB0aGUgcmVzdAoKCiMjIF9QcmludCBwcm9iYWJpbGl0aWVzIGZvciBlYWNoIHNvbmcgdG8gYmVsb25nIHRvIGVhY2ggdG9waWMKCmBgYHtyfQpsb2FkKGZpbGUgPSAib2JqZWN0cy9zb25nc19sZGFfMy5SREEiKQoKCnNvbmdzX2dhbW1hIDwtIAogIHRpZHkoc29uZ3NfbGRhLCBtYXRyaXggPSAiZ2FtbWEiKSAlPiUgCiAgYXJyYW5nZShkb2N1bWVudCwgdG9waWMpCgpgYGAKCgojIyBfVG9wIHRlcm1zIHBlciBUb3BpYwoKYGBge3J9CiAjIF9DYWxjdWxhdGUgVGFibGVzICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICBsaWJyYXJ5KHRpZHl0ZXh0KQogIAogIGFwX3RvcGljcyA8LSB0aWR5KHNvbmdzX2xkYSwgbWF0cml4ID0gImdhbW1hIikKICAKICB0b3BfdGVybXMgPC0gCiAgICBhcF90b3BpY3MgJT4lCiAgICBncm91cF9ieSh0b3BpYykgJT4lCiAgICB0b3BfbigxMCwgZ2FtbWEpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgYXJyYW5nZSh0b3BpYywgLWdhbW1hKSAlPiUgCiAgICByZW5hbWUocHJvYiA9IGdhbW1hKQogIAogIHRvcF90ZXJtcwpgYGAKCgojIyBfQXJlIHRvcGljcyBhbmQgZ2VucmVzIHJlbGF0ZWQ/CgpgYGB7cn0KIyBfQ2FsY3VsYXRlIFRhYmxlcyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmxpYnJhcnkodGlkeXRleHQpCiAgCmFwX3RvcGljcyA8LSB0aWR5KHNvbmdzX2xkYSwgbWF0cml4ID0gImdhbW1hIikKCiAgCnRlc3QgPC0gcmlnaHRfam9pbihhcF90b3BpY3MsIHNvbmdzWywgYygic29uZyIsICJnZW5yZSIpXSwgYnkgPSBjKCJkb2N1bWVudCIgPSAic29uZyIpKQogCgojIHJlb3JkZXIgdGl0bGVzIGluIG9yZGVyIG9mIHRvcGljIDEsIHRvcGljIDIsIGV0YyBiZWZvcmUgcGxvdHRpbmcKdGVzdCAlPiUKICBtdXRhdGUoZ2VucmUgPSByZW9yZGVyKGdlbnJlLCBnYW1tYSAqIHRvcGljKSkgJT4lCiAgZ2dwbG90KGFlcyhmYWN0b3IodG9waWMpLCBnYW1tYSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZmFjZXRfd3JhcCh+IGdlbnJlKQoKCmBgYAoqKiogMSBUb3BpYyBhcmUgbW9zdCBvZiBnZW5yZXMuIFBPUCwgUiZCLCBDb3VudHJ5Li4uCioqKiBUaGUgMm5kIHRvcGljIGlzIGRvbWluYXRlZCBieSBIaXAtSG9wLgoqKiogVGhlIDNyZCB0b3BpYyBpcyBkb21pbmF0ZWQgYnkgTWV0YWwgZ2VucmUuIGFsdGhvdWdoIHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgY29udHJpYnV0aW9uIApvZiBGb2xrIG11c2ljCgoK